/*=============================================================================
#    The element-comm is a tentative program used to test our ideas.           
#                       Copyright (C)  bgao                                    
#
#     This program is free software; you can redistribute it and/or            
#      modify it under the terms of the GNU General Public License             
#     as published by the Free Software Foundation; either version 2           
#         of the License, or (at your option) any later version.               
#
#     This program is distributed in the hope that it will be useful,          
#    but WITHOUT ANY WARRANTY; without even the implied warranty of           
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            
#             GNU General Public License for more details.                    
#
#    You should have received a copy of the GNU General Public License        
#     along with this program; if not, write to the Free Software             
#      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,             
#                       MA  02110-1301, USA.                                  
#==============================================================================
# $Id: mac_tx.c 348 2010-11-29 09:01:16Z bgao $ 
#
# $Author: bgao $ 
#
# $Revision: 348 $ 
#
# $Date: 2010-11-29 17:01:16 +0800 (星期一, 29 十一月 2010) $ 
#
# Description: 
#
=============================================================================*/
/*! @file mac_tx.c
 *  @brief This file implements the MAC transmission functionality,
 *         which includes CSMA/CA mechanism, indirect buffer and
 *         acknowlegement trigger mechanism.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mac.h"

static int8 mac_delay(uint32 units);

/*! check the way of transmission and ack mechanism is used before send out.
 *  @param buf pointer to the buf structure to be transmit.
 *  @param addr pointer to the structure of address.
 *  @param retry indicate if the ack mechanism is used.
 *  @param indir indicate if the indirect transmission is used.
 *  @param handle the identifier of the frame used by the upper layer.
 *  @param dsn the data sequence number of the frame.
 *  @return indicate the results of this function.
 */
int8 mac_handle_tx(buf_t *buf, addr_t *addr, bool retry, bool indir, uint8 handle, uint8 dsn)
{
    int8 r;

    if (indir) {
        mac_indir_t *i;

        if (addr == NULL) {
            /* confirm the nwk layer that error occurs, which is handled by caller */
            return MAC_INVALID_PARAMETER;
        }

        i = mac_indir_alloc();
        if (i == NULL) {
            /* confirm the nwk layer that error occurs */
            return MAC_TRANSACTION_OVERFLOW;
        } else {
            i->dsn = dsn;
            i->handle = handle;
            memcpy((void *)&(i->addr), (void *)addr, sizeof(addr_t));
            i->buf = buf;
            return MAC_OK;
        }
    }

    if (retry) {
        mac_retry_t *r;

        r = mac_retry_alloc();
        if (r == NULL) {
            /* TODO confirm the nwk layer that error occurs, which is handled by the caller */
            MAC_DEBUG("mac_handle_tx: mac_retry_alloc() returns a NULL\n");
            return MAC_TRANSACTION_OVERFLOW;
        } else {
            r->dsn = dsn;
            r->handle = handle;
            r->buf = buf;
        }
    }

    MAC_DEBUG("\nmac_handle_tx: got here\n");

    r = mac_csmaca_tx(buf, dsn, retry);
    return r;
}

/*! send the frame using CSMA-CA mechanism and then using radio's tx.
 *  @param buf pointer to the buf strucure to be sent.
 *  @param dsn the data sequence number.
 *  @param retry indicate if acknowlegement is used.
 *  @return return the results of this function.
 */
int8 mac_csmaca_tx(buf_t *buf, uint8 dsn, bool retry)
{
    uint8 nb;                           /*!< number of backoff times. */
    uint8 be = mac_get_min_be();        /*!< backoff exponent. */
    uint8 max_be = mac_get_max_be();
    uint8 bp = 0;                       /*!< backoff period. */
    int8 limit = mac_get_max_csma_backoffs();
    bool is_sent;

    MAC_DEBUG("mac_csmaca_tx: min_be is %d\n", be);
    MAC_DEBUG("mac_csmaca_tx: max_be is %d\n", max_be);
    MAC_DEBUG("mac_csmaca_tx: max_csma_backoffs is %d\n", limit);

    /* load the frame into the radio fifo buffer */
    rf_write_tx_fifo(buf->ptr, buf->length);

    for (nb = 0; nb < limit; nb++) {
        bp = rf_get_rand() % ((1 << be) - 1);
        mac_delay(bp);
        /* perform CCA */
        is_sent = rf_tx_cca_on();
        if (is_sent) {
            return MAC_OK;
        } else {
            be = ((be+1)<max_be) ? (be+1) : max_be;
        } 
    }
        
    if (nb == limit) {
        if (retry == true) {
            mac_retry_free(dsn);
        } else {
            buf_free(buf);
        }
        return MAC_CHANNEL_ACCESS_FAILURE;
    }
    return MAC_OK;
    /* the confirmation is handled by the MAC's primitive layer */
}

/*! delay for units periods.
 *  @param units units to delay.
 *  @return indicate result of this function.
 */
static int8 mac_delay(uint32 units)
{
    int a;
    if (units <= 0) {
        return MAC_ERR;
    }

    while (units--) {
        a = 10000;
        while (a--) {
            ;
        }
    }

    return MAC_OK;
}

